package sisop;

import java.util.LinkedList;
import java.io.*;

/**
 * Implementacion de un scheduler 
 * Round Robin. Esta clase esta vacia
 */ 
class RR extends Scheduler {

	private int finished_tasks;
	private LinkedList<Task> current_tasks;
	private int current_time;
	private Task current_task;
	private int round_time;
	private int switch_time;
	
	private int quantum = DEFAULT_QUANTUM;

	/**
	 * Valor del quantum por defecto.
	*/
	public static final int DEFAULT_QUANTUM = 5;

	/**
	* Construye un planificador Round Robin
	*/ 
	RR() {
		super("RR");
	}

	/**
	 * Permite indicar el valor del quantum
	 * deseado para la planificacion
	 */
	public void set_quantum(int q) {
		this.quantum = q;
	}

	protected void scheduler_init() {
		if (this.task_set.get_max_rtime()<0)
			throw new IllegalStateException("Cannot schedule a task_set with release time<0");

		finished_tasks=0;
		current_time=-1;
		current_task=null;
		current_tasks=new LinkedList<Task>();
		round_time=0;
		switch_time=2;
	}

	public String scheduler_next() {
	
		current_time++;

		SelectReadyTasks();

		if (switch_time<2)
		{
			switch_time++;
			return IDLE_TASK;
		}
		else
		{
			if (current_task!=null && (current_task.ttime>=current_task.ptime || round_time>=quantum))
			{
				current_tasks.remove();
				current_task.ftime=current_time;

				if (current_task.ttime<current_task.ptime)
				{
					current_tasks.addLast(current_task);
				}
				else
				{
					//current_task.ftime=current_time;
					finished_tasks++;
					
					if (task_set.size()==finished_tasks)
						return null;
				}

				switch_time=1;
				current_task=null;
				return IDLE_TASK;
			}
			else
			{
				if (current_task==null)
				{
					if (current_tasks.size()>0)
					{
						current_task = current_tasks.getFirst();
						current_task.wtime += (current_task.ftime<0 ? current_time-current_task.rtime :current_time-current_task.ftime);
						round_time=0;
					}
					else
					{
						return IDLE_TASK;
					}
				}
				
				current_task.ttime++;
				round_time++;
			}
		}
		
		return current_task.name;
	}

	private void SelectReadyTasks() {
		for (Task task: this.task_set)
			if (task.rtime==current_time)
				current_tasks.add(task);
	}

}
